package org.linlinjava.litemall.web.controller;

import static org.linlinjava.litemall.web.util.WebResponseCode.AUTH_INVALID_ACCOUNT;
import static org.linlinjava.litemall.web.util.WebResponseCode.AUTH_NOT_PERMISSION;

import java.time.LocalDateTime;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

import javax.servlet.http.HttpServletRequest;
import javax.validation.Valid;

import cn.hutool.core.util.ObjectUtil;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import io.swagger.annotations.*;
import org.linlinjava.litemall.core.config.DynamicTimeZoneConfiguration;
import org.linlinjava.litemall.core.util.IpUtil;
import org.linlinjava.litemall.core.util.JacksonUtil;
import org.linlinjava.litemall.core.util.ResponseUtil;
import org.linlinjava.litemall.core.util.ResponseUtil.Response;
import org.linlinjava.litemall.core.util.bcrypt.BCryptPasswordEncoder;
import org.linlinjava.litemall.db.domain.*;
import org.linlinjava.litemall.db.service.*;
import org.linlinjava.litemall.db.util.SpringUtils;
import org.linlinjava.litemall.web.annotation.LogAnno;
import org.linlinjava.litemall.web.annotation.LoginShop;
import org.linlinjava.litemall.web.annotation.LoginUser;
import org.linlinjava.litemall.web.dto.AdminUserInfoDTO;
import org.linlinjava.litemall.web.service.UserTokenManager;
import org.linlinjava.litemall.web.service.WebSettlementLogService;
import org.linlinjava.litemall.web.vo.AuthKnockOffRequest;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

/**
 * web身份验证控制器
 * 鉴权服务
 *
 * @author yliyun
 * @date 2022/09/14
 */
@Api(value="鉴权controller",tags={"鉴权操作接口"})
@RestController
@RequestMapping("/web/auth")
@Validated
public class WebAuthController {

    /**
     * 用户服务
     */
    @Autowired
	private LitemallUserService userService;
    /**
     * 店服务
     */
    @Autowired
    private LitemallShopService shopService;
    /**
     * 管理服务
     */
    @Autowired
    private LitemallAdminService adminService;
    /**
     * 解决日志服务
     */
    @Autowired
    private WebSettlementLogService settlementLogService;
    /**
     * 订单服务
     */
    @Autowired
    private LitemallOrderService orderService;
    @Autowired
    private LitemallTokenService litemallTokenService;

    @Autowired
    private DynamicTimeZoneConfiguration dynamicTimeZoneConfiguration;


    /**
     * 登录
     * 账号登录，此账号为普通用户账号和系统用户账号
     * 普通用户账号为系统生成、账号密码应和系统用户一致
     *
     * @param body    请求内容，{ username: xxx, password: xxx }
     * @param request 请求对象
     * @return 登录结果
     */
    @ApiOperation(value="账号登录")
    @PostMapping("login")
    @LogAnno
    @ApiImplicitParams({
                    @ApiImplicitParam(name="body",paramType = "body",dataType = "String"),
            })
    public Object login(@RequestBody String body, HttpServletRequest request) {
        String username = JacksonUtil.parseString(body, "username");
        String password = JacksonUtil.parseString(body, "password");
        if (username == null || password == null) {
            return ResponseUtil.badArgument();
        }

        //验证普通用户
        List<LitemallUser> userList = userService.list(Wrappers.lambdaQuery(LitemallUser.class)
                .eq(LitemallUser::getUsername,username.toLowerCase())
                .eq(LitemallUser::getInnerAccount,1)
        );

        LitemallUser user = null;
        if (userList.size() > 1) {
            return ResponseUtil.serious();
        } else if (userList.size() == 0) {
            return ResponseUtil.fail(AUTH_INVALID_ACCOUNT, "账号不存在");
        } else {
            user = userList.get(0);
            if(!user.getInnerAccount()){
                return ResponseUtil.fail(AUTH_INVALID_ACCOUNT, "账号不存在");
            }
        }

        BCryptPasswordEncoder encoder = new BCryptPasswordEncoder();
        if (!encoder.matches(password, user.getPassword())) {
            return ResponseUtil.fail(AUTH_INVALID_ACCOUNT, "账号密码不对");
        }


        // 验证是否为门店系统用户
        List<LitemallAdmin> admins = adminService.findAdmin(username);
        LitemallAdmin admin = null;
        if (admins.size() > 1) {
            return ResponseUtil.serious();
        } else if (admins.size() == 0) {
            return ResponseUtil.fail(AUTH_NOT_PERMISSION, "无权限的账号");
        } else {
            admin = admins.get(0);
        }
        BCryptPasswordEncoder encoderAdmin = new BCryptPasswordEncoder();
        if (!encoderAdmin.matches(password, admin.getPassword())) {
            return ResponseUtil.fail(AUTH_INVALID_ACCOUNT, "账号密码不对");
        }

        // 更新登录情况
        user.setLastLoginTime(LocalDateTime.now());
        user.setLastLoginIp(IpUtil.getIpAddr(request));
        if (userService.updateById2(user)==0) {
            return ResponseUtil.updatedDataFailed();
        }

        // userInfo
        AdminUserInfoDTO userInfo = new AdminUserInfoDTO();
        userInfo.setNickName(username);
        userInfo.setAvatarUrl(user.getAvatar());

        // token
        String token = UserTokenManager.generateToken(user.getId(), admin.getShopId());
        //存储token
        /*LitemallToken litemallToken = LitemallToken.builder()
                .userId(user.getId()).serve(3)
                .device(3).validDays(4)
                .token(token.toString()).valid(0)
                .loginTime(LocalDateTime.now())
                .build();
        //device还不确定具体登陆设备

        List<LitemallToken> litemallTokens = litemallTokenService.list(Wrappers.lambdaQuery(LitemallToken.class)
                .eq(LitemallToken::getUserId, user.getId())
                .eq(LitemallToken::getValid, 0));
        if(litemallTokens.size()>0){
            litemallTokens.stream().forEach(litemallToken1 -> litemallToken1.setValid(1));
            //有另一端登陆 「不许登陆」
            return ResponseUtil.serious();
        }
        litemallTokenService.save(litemallToken);*/

        Map<Object, Object> result = new HashMap();
        result.put("token", token);
        result.put("userInfo", userInfo);
        dynamicTimeZoneConfiguration.setDynamicTimeZone(shopService.findById(admin.getShopId()).getTimezone());
        return ResponseUtil.ok(result);
    }

    /**
     * 注销
     *
     * @param userId 用户id
     * @return {@link Object}
     */
    @ApiOperation(value="账号登出")
    @PostMapping("logout")
    @LogAnno
    @Transactional
    public Object logout(@LoginUser Integer userId) {
        if (userId == null) {
            return ResponseUtil.unlogin();
        }
        LitemallToken litemallToken = litemallTokenService.getOne(Wrappers.lambdaQuery(LitemallToken.class)
                .eq(LitemallToken::getUserId,userId)
                .eq(LitemallToken::getServe, 2)
                .eq(LitemallToken::getValid, 0));
        if(ObjectUtil.isNull(litemallToken)){
            return ResponseUtil.ok();
        }
        //清除令牌
        litemallTokenService.removeById(litemallToken);
        //用户正常登出把关于用户的新建和挂起的订单删除
        Short[] orderStatus = {1,101};
        List<LitemallOrder> orders =  orderService.queryByOrderStatus(userId, Arrays.asList(orderStatus),false);
        orders.stream().forEach(order -> {
            LitemallOrder o = new LitemallOrder();
            o.setId(order.getId());
            o.setDeleted(true);
            orderService.updateById(o);
        });
        return ResponseUtil.ok();
    }

    /**
     * 信息
     *
     * @param userId 用户id
     * @param shopId 商店id
     * @return {@link Object}
     */
    @ApiOperation(value="账号信息")
    @GetMapping("info")
    @LogAnno
    public Object info(@LoginUser Integer userId, @LoginShop Integer shopId) {
        if (userId == null) {
            return ResponseUtil.unlogin();
        }

        LitemallUser user = userService.findById(userId);
        Map<Object, Object> data = new HashMap<Object, Object>();
        data.put("nickName", user.getNickname());
        data.put("name", user.getUsername());
        data.put("avatar", user.getAvatar());
        data.put("gender", user.getGender());
        data.put("mobile", user.getMobile());
        data.put("email", user.getEmail());
        data.put("id", user.getId());
        data.put("shopId", shopId);
        LitemallShop shop = shopService.findById(shopId);
        data.put("shop", shop);

        return ResponseUtil.ok(data);
    }

    /**
     * 下班
     * ipad用户下班
     *
     * @param shopId  商店id
     * @param userId  用户id
     * @param request 请求
     * @return {@link Response}<{@link Object}>
     */
    @ApiOperation(value="交接")
    @PostMapping("knockoff")
    @LogAnno
    public Response<Object> knockOff(@ApiParam(name="shopId",value="登录的店铺id",required=true) @LoginShop Integer shopId,
    		@ApiParam(name="userId",value="登录的用户id",required=true) @LoginUser Integer userId,
    		@Valid @RequestBody @ApiParam(name="request",value="交接请求对象",required=true) AuthKnockOffRequest request) {
        if (userId == null) {
            return ResponseUtil.unlogin();
        }

        return settlementLogService.add(shopId, userId, request);
    }

}
